package myJs.user.workflow.featureSelection.preprocess

import com.softwaremill.quicklens._
import myJs.Utils.layer
import myJs.cps._
import myJs.myPkg.LayerOptions
import myJs.myPkg.reactHookForm._
import myJs.tool.Tool
import myJs.tool.Tool.messages
import shared.Pojo.{EachPreprocessData, FsPreprocessData}

import scala.scalajs.js
import myJs.Implicits._
import myJs.user.FeatureSelectionTool
import shared.pojo.WorkflowMission.ExtraData

import scala.scalajs.js
import myJs.Implicits._

import japgolly.scalajs.react.vdom.all._
import japgolly.scalajs.react._
import japgolly.scalajs.react.React.Fragment
import japgolly.scalajs.react.util.EffectCatsEffect._
import myJs.myPkg.Hooks._
import cats.effect._
import myJs.Implicits._
import myJs.Utils._

/** Created by yz on 3/11/2020
  */
object PreprocessCp {

  case class Props(
      preProcess: FsPreprocessData,
      preProcessChange: FsPreprocessData => SyncIO[Unit],
      extraData: ExtraData
  ) {
    @inline def render: VdomElement = {
      Component(this)
    }
  }

  val Component =
    ScalaFnComponent[Props] { props =>
      val useForm = ReactHookForm.useFormContext()
      val namePrefix = s"preprocess"

      val useFieldArray = ReactHookForm.useFieldArray(
        UseFieldArrayOptions(
          name = s"preprocess.datas"
        )
      )

      object FTool {

        def useTrainChange = (v: Boolean) => {
          val newPreProcess = props.preProcess.modify(_.useTrain).setTo(v)
          props.preProcessChange(newPreProcess)
        }

        def trainPercentChange = (v: String) => {
          val newPreProcess = props.preProcess.modify(_.trainPercent).setTo(v)
          props.preProcessChange(newPreProcess)
        }

        def seedChange = (v: String) => {
          val newPreProcess = props.preProcess.modify(_.seed).setTo(v)
          props.preProcessChange(newPreProcess)
        }

        def datasChange = (vs: List[EachPreprocessData]) => {
          val newPreProcess = props.preProcess.modify(_.datas).setTo(vs)
          props.preProcessChange(newPreProcess)
        }

        def addModule(moduleName: String) = {
          val c = AllCp.kindCpMap(moduleName)
          if (c == ExtraNormalCp && props.extraData.groupHeaders.isEmpty) {
            SyncIO {
              layer.msg(
                messages("noAdditionalDataColumnsForGroupingInformation"),
                LayerOptions.icon(5).time(3000)
              )
              ()
            }
          } else {
            val newData = EachPreprocessData(
              kind = moduleName,
              rowName = props.extraData.rowNames.head,
              extraColumn = props.extraData.groupHeaders.headOption.getOrElse("")
            )
            val newPreProcess =
              props.preProcess.modify(_.datas).using(_ :+ newData)
            useFieldArray.append(newData)
            props.preProcessChange(newPreProcess)
          }
        }

        def insertModule(curI: Int) = (moduleName: String) => {
          val c = AllCp.kindCpMap(moduleName)
          if (c == ExtraNormalCp && props.extraData.groupHeaders.isEmpty) {
            SyncIO {
              layer.msg(
                messages("noAdditionalDataColumnsForGroupingInformation"),
                LayerOptions.icon(5).time(3000)
              )
            }.void
          } else {
            val newData = EachPreprocessData(
              kind = moduleName,
              rowName = props.extraData.rowNames.head,
              extraColumn = props.extraData.groupHeaders.headOption.getOrElse("")
            )
            val newPreProcess =
              props.preProcess.modify(_.datas).using(_.insert(curI, newData))
            useFieldArray.insert(curI, newData)
            props.preProcessChange(newPreProcess)
          }
        }

        def removeModule = (curI: Int) => {
          SyncIO {
            useFieldArray.remove(curI)
          } >> {
            val newPreProcess = props.preProcess.modify(_.datas).using { x =>
              x.removed(curI)
            }
            props.preProcessChange(newPreProcess)
          }
        }

      }

      val formState = ReactHookForm.useFormState(options =
        UseFormStateOptions(
          name = namePrefix
        )
      )

      useEffect(
        SyncIO {
          Tool.refreshNodeColor(
            props.preProcess.nodeId,
            useForm.formState,
            namePrefix
          )
        },
        List(formState)
      )

      div(
        useFieldArray.fields.toList.zipWithIndex.toVdomArray { case (item, curI) =>
          val data = props.preProcess.datas.getOrElse(curI, EachPreprocessData())
          AllCp.kindCpMap
            .get(data.kind)
            .map { c =>
              div(
                key := s"${item.id}",
                c.cp(
                  curI = curI,
                  datas = props.preProcess.datas,
                  datasChange = FTool.datasChange,
                  insertModule = FTool.insertModule(curI),
                  removeModule = FTool.removeModule,
                  extraData = props.extraData
                )
              )
            }
            .getOrElse(div())
        },
        div(
          className := "form-group",
          marginTop := "10px",
          marginBottom := "10px",
          div(
            className := "btn-group",
            button(
              `type` := "button",
              className := "btn btn-default dropdown-toggle",
              dataToggle := "dropdown",
              width := "100%",
              marginTop := "5px",
              title := messages("add"),
              s"${messages("addANewStep")} ",
              span(className := "caret")
            ),
            ul(
              className := "dropdown-menu",
              role := "menu",
              marginTop := "6px",
              minWidth := "120px",
              AllCp.cps.toVdomArray { c =>
                li(
                  key := s"${c.nameStr}",
                  a(
                    s"${messages(c.nameStr)}",
                    onClick --> FTool.addModule(c.nameStr)
                  )
                )
              }
            )
          )
        ),
        ToggleCp
          .Props(
            value = props.preProcess.useTrain,
            label = messages("useTrain"),
            name = "useTrain",
            questionInfo = messages("useTrainInfo"),
            valueChange = FTool.useTrainChange
          )
          .render,
        InputGroupCp
          .Props(
            value = props.preProcess.trainPercent,
            label = messages("trainSetRatio"),
            show = props.preProcess.useTrain,
            name = "preprocess.trainPercent",
            onChange = FTool.trainPercentChange
          )
          .render,
        InputCp
          .Props(
            value = props.preProcess.seed,
            label = "Seed",
            show = props.preProcess.useTrain,
            name = "seed",
            onChange = FTool.seedChange
          )
          .render
      )

    }

}
